5.22

改进这章的 write 的减半本本, 接受用户名作为参数, 处理特殊情况, 显示欢迎信息

#include <stdio.h>
#include <utmp.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>

#define DEBUG

char *peertty(struct utmp [], size_t);
char *welcome(struct utmp[], size_t);

    int
main( int argc, char **argv )
{
    if (argc != 2){
        fprintf(stderr, "usage: %s [username]\n", argv[0]);
        return 1;
    }
    struct utmp buf, bufs[BUFSIZ];
    struct stat info;
    int utmpfd, i, k = 0, reclen = sizeof(struct utmp);
    if ((utmpfd = open(UTMP_FILE, O_RDONLY)) == -1){
        perror("read utmp ");
        return 2;
    }

    for (i = 0; i < BUFSIZ; i++){
        if (read(utmpfd, &buf, reclen) == reclen){
            if (buf.ut_type == USER_PROCESS && strcmp(buf.ut_user, argv[1]) == 0){
                bufs[k] = buf;
                k++;
            }
        }
    }
    close(utmpfd);

    if (k == 0){
        fprintf(stderr, "%s is not login\n", argv[1]);
        return 3;
    }

    char *devs = peertty(bufs, k);
    if (k > 1){
        printf("%s logged in more than once; writing to: %s\n", argv[1], devs);
    }
#ifdef DEBUG
    printf("%s\n", devs);
#endif
    if (stat(devs, &info) == 0){
#ifdef DEBUG
        printf("%d-%d", info.st_mode, info.st_mode & (S_IWGRP | S_IWOTH));
#endif
        if ((info.st_mode & (S_IWGRP|S_IWOTH)) == 0){
            fprintf(stderr, "%s is block the message\n", argv[1]);
            return 5;
        }
    }else{
        perror("stat ");
        return 4;
    }

    int wfd;
    if ((wfd = open(devs, O_RDWR | O_APPEND)) == -1){
        perror("open");
        return 6;
    }
    char *wstr = welcome(bufs, k);
    if (write(wfd, wstr, sizeof(char) * strlen(wstr)) == -1){
        perror("write ");
        return 9;
    }
    char c;
    while((c = getchar())){
        if (write(wfd, &c, sizeof(c)) == -1){
            perror("write");
            return 8;
        }
    }

    return 0;
}

char *line2devpath(char *line)
{
    char devs[13] = "/dev/";
    strcat(devs, line);
    return strdup(devs);
}

char *peertty(struct utmp utmpbufs[], size_t t){
    char *devs, *cur = ttyname(1);
#ifdef DEBUG
    printf("size %ld\n", t);
#endif

    if (t == 1){
        return line2devpath(utmpbufs[0].ut_line);
    }

    unsigned int i;
#ifdef DEBUG
    printf("cur tty %s\n", cur);
#endif

    for (i = 0; i < t; i++){
        devs = line2devpath(utmpbufs[i].ut_line);
        if (strcmp(devs, cur) != 0){
            return devs;
        }
    }
    return line2devpath(utmpbufs[0].ut_line);
}

char *welcome(struct utmp ubufs[], size_t n)
{
    char *curtty = ttyname(1), wstr[BUFSIZ];
    time_t rawtime;
    unsigned int i;
    for (i=0; i < n; i++){
        if (strcmp(line2devpath(ubufs[i].ut_line), curtty) == 0){
            time(&rawtime);
            sprintf(wstr,"Message from %s@%s on %s at %s\n", ubufs[i].ut_user, ubufs[i].ut_host, ubufs[i].ut_line, ctime(&rawtime));
#ifdef DEBUG
            printf("wstr %s\n", wstr);
#endif
            return strdup(wstr);
        }
    }
}

5.23

编写mesg, 查看源码 mesg 就是关闭当前tty的 组和其他用户的写权限来实现

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>

    int
main( int argc, char **argv )
{
    if ((argc == 2 && strlen(argv[1]) == 1) && (argv[1][0] != 'y' && argv[1][0] != 'n')){
        fprintf(stderr, "usage: %s y|n\n", argv[0]);
        return 1;
    }
    char *tty = ttyname(1);
    char r = 'n';
    struct stat info;

    if (stat(tty, &info) == -1){
        perror("stat");
        return 1;
    }

    if (argc == 1){
        if (info.st_mode & (S_IWGRP|S_IWOTH)){
            r = 'y';
        }
        printf("%s %c\n", argv[0], r);
        return 0;
    }

    if (argv[1][0] == 'y'){
        if (chmod(tty,info.st_mode | S_IWGRP | S_IWOTH) == -1){
            perror("chmod");
            return 1;
        }
    }else {
        if (chmod(tty, info.st_mode & ~(S_IWGRP | S_IWOTH))){
            perror("chmod");
            return 1;
        }
    }
    return 0;
}